/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.apiGenerator.dataType.entityInterface.resourceInfo.initcolumnsstragety;

import com.inspur.edp.caf.generator.utils.ExpressionUtils;
import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.AssoCondition;
import com.inspur.edp.cef.designtime.api.element.GspAssociation;
import com.inspur.edp.cef.generator.apiGenerator.dataType.entityInterface.DataTypeInterfaceGeneratorContext;
import com.inspur.edp.cef.generator.apiGenerator.dataType.entityInterface.resourceInfo.InitColumnsGenerator;
import com.inspur.edp.cef.spi.entity.AssociationEnableState;
import com.inspur.edp.cef.spi.entity.AssociationInfo;
import com.inspur.edp.cef.spi.entity.info.propertyinfo.AssocationPropertyInfo;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.entity.GspCommonModel;
import org.eclipse.jdt.core.dom.*;

public class AddAssociationColumnStategory extends BaseAddColumnStragety {

  public AddAssociationColumnStategory(Block block,
      IGspCommonDataType commonDataType,
      IGspCommonField field, AST ast,
      DataTypeInterfaceGeneratorContext parentContext,
      ExtendAddPropertyInfoProcessor extendAddPropertyInfoProcessor) {
    super(block, commonDataType, field, ast, parentContext, extendAddPropertyInfoProcessor);
  }

  private String getAssoInfoVarName() {
    return "objectType"+field.getLabelID();
  }

  @Override
  protected void addComplexAddStatement(MethodInvocation methodInvocation) {
    addDisplayValueKeyStatement(methodInvocation);
    addRequiredArgStatement(methodInvocation);
    addEnableRtrimStatement(methodInvocation);
    addLengthStatement(methodInvocation);
    addDefaultNullStatment(methodInvocation);
    addAssoInfoStatement(methodInvocation);
    addAssClassStatement(methodInvocation);
  }

  @Override
  protected void addSimpleAddStatement(MethodInvocation methodInvocation) {
   addRequiredArgStatement(methodInvocation);
   addEnableRtrimStatement(methodInvocation);
   addAssoInfoStatement(methodInvocation);
   addAssClassStatement(methodInvocation);
  }

  private void addAssClassStatement(MethodInvocation methodInvocation) {
//String assoType =parentContext.getApiGenContext().getCefGenContext().getEntityGenContext()
//    .getElementAssociationTypes().get(field.getID()).getFullName();
//      TypeLiteral typeLiteral = ast.newTypeLiteral();
//      typeLiteral
//          .setType(new TypeInfo(assoType).getType(ast, parentContext.getApiGenContext()));
//      methodInvocation.arguments().add(typeLiteral);
  }

  protected final void addAssoInfoStatement(MethodInvocation methodInvocation) {
    methodInvocation.arguments().add(ast.newSimpleName(getAssoInfoVarName()));
  }

  @Override
  protected void beforeAddMethodInvocation() {
    super.beforeAddMethodInvocation();
    GspAssociation association = ( field).getChildAssociations().get(0);
    String varName = getAssoInfoVarName() ;
    String[] info = InitColumnsGenerator. parseRef(association,parentContext);
    AssociationInfo ass = InitColumnsGenerator. getAssociationInfo(this.parentContext, association, commonDataType);
   String assoType = parentContext.getApiGenContext().getCefGenContext().getEntityGenContext()
        .getElementAssociationTypes().get(field.getID()).getFullName();
    VariableDeclarationStatement statement= (VariableDeclarationStatement) InitColumnsGenerator.buildCreateAssoStatement(ast,parentContext,varName,info,association,ass.getPrivateSourceColumn(),ass.getPrivateTargetColumn(),
        AssocationPropertyInfo.class,assoType);
    block.statements().add(statement);
    buildAssoCondiStatements(association, varName);
    addRefColumnsStatements(association, varName);
  }

  protected void buildAssoCondiStatements(GspAssociation association, String varName){
    if(association.getAssoConditions() != null && association.getAssoConditions().size() >0){

//      ArrayList<AssoCondition> objectTypeass1Condis = new ArrayList<>();
      String condiListVarName = varName+"Condis";
      VariableDeclarationFragment condisFragement = ast.newVariableDeclarationFragment();
      condisFragement.setName(ast.newSimpleName(condiListVarName));
      ClassInstanceCreation classInstanceCreation = ast.newClassInstanceCreation();
      ParameterizedType parameterizedType = ast.newParameterizedType(ast.newSimpleType(ast.newSimpleName("ArrayList")));
      classInstanceCreation.setType(parameterizedType);
      condisFragement.setInitializer(classInstanceCreation);

      ParameterizedType parameterizedType2 = ast.newParameterizedType(ast.newSimpleType(ast.newSimpleName("ArrayList")));
      parameterizedType2.typeArguments().add(ast.newSimpleType(ast.newSimpleName("AssoCondition")));

      VariableDeclarationStatement condisStatement = ast.newVariableDeclarationStatement(condisFragement);
      condisStatement.setType(parameterizedType2);
      block.statements().add(condisStatement);
      int index = 0;

      for(AssoCondition condition: association.getAssoConditions()){
        VariableDeclarationFragment fragment = ast.newVariableDeclarationFragment();
        String condiVarName = varName + "Condi" + (index++);
        fragment.setName(ast.newSimpleName(condiVarName));

        ClassInstanceCreation classInstanceCreation1 = ast.newClassInstanceCreation();
        classInstanceCreation1.setType(ast.newSimpleType(ast.newSimpleName("AssoCondition")));
        fragment.setInitializer(classInstanceCreation1);

        VariableDeclarationStatement variableDeclarationStatement = ast.newVariableDeclarationStatement(fragment);
        variableDeclarationStatement.setType(ast.newSimpleType(ast.newSimpleName("AssoCondition")));
        block.statements().add(variableDeclarationStatement);

        MethodInvocation leftNodeCodeMethod = ExpressionUtils.getMethodInvocation(ast, condiVarName, "setLeftNodeCode");
        StringLiteral leftNodeLiteral=ast.newStringLiteral();
        leftNodeLiteral.setLiteralValue(condition.getLeftNodeCode());
        leftNodeCodeMethod.arguments().add(leftNodeLiteral);
        block.statements().add(ast.newExpressionStatement(leftNodeCodeMethod));

        MethodInvocation leftNodeFieldMethod = ExpressionUtils.getMethodInvocation(ast, condiVarName, "setLeftField");
        StringLiteral leftFieldLiteral=ast.newStringLiteral();
        leftFieldLiteral.setLiteralValue(condition.getLeftField());
        leftNodeFieldMethod.arguments().add(leftFieldLiteral);
        block.statements().add(ast.newExpressionStatement(leftNodeFieldMethod));

        MethodInvocation operatorMethod = ExpressionUtils.getMethodInvocation(ast, condiVarName, "setOperator");
        StringLiteral operatorLiteral=ast.newStringLiteral();
        operatorLiteral.setLiteralValue(condition.getOperator());
        operatorMethod.arguments().add(operatorLiteral);
        block.statements().add(ast.newExpressionStatement(operatorMethod));

        MethodInvocation rightNodeCodeMethod = ExpressionUtils.getMethodInvocation(ast, condiVarName, "setRightNodeCode");
        StringLiteral rightNodeLiteral=ast.newStringLiteral();
        rightNodeLiteral.setLiteralValue(condition.getRightNodeCode());
        rightNodeCodeMethod.arguments().add(rightNodeLiteral);
        block.statements().add(ast.newExpressionStatement(rightNodeCodeMethod));

        MethodInvocation rightFieldCodeMethod = ExpressionUtils.getMethodInvocation(ast, condiVarName, "setRightField");
        StringLiteral rightFieldLiteral=ast.newStringLiteral();
        rightFieldLiteral.setLiteralValue(condition.getRightField());
        rightFieldCodeMethod.arguments().add(rightFieldLiteral);
        block.statements().add(ast.newExpressionStatement(rightFieldCodeMethod));

        MethodInvocation valueMethod = ExpressionUtils.getMethodInvocation(ast, condiVarName, "setValue");
        StringLiteral valueLiteral=ast.newStringLiteral();
        valueLiteral.setLiteralValue(condition.getValue());
        valueMethod.arguments().add(valueLiteral);
        block.statements().add(ast.newExpressionStatement(valueMethod));

        MethodInvocation addMethod = ExpressionUtils.getMethodInvocation(ast, condiListVarName, "add");
        addMethod.arguments().add(ast.newSimpleName(condiVarName));
        block.statements().add(ast.newExpressionStatement(addMethod));
      }

      MethodInvocation getAsso = ExpressionUtils.getMethodInvocation(ast, varName, "getAssociationInfo");
      MethodInvocation setAsso = ExpressionUtils.getMethodInvocation(ast, getAsso, "setAssoConditions");
      setAsso.arguments().add(ast.newSimpleName(condiListVarName));
      block.statements().add(ast.newExpressionStatement(setAsso));
    }
  }

  protected  void addRefColumnsStatements(GspAssociation association, String varName) {
    for (IGspCommonField refEle : association.getRefElementCollection()) {
      MethodInvocation invocation = ExpressionUtils.getMethodInvocation(ast, varName,
          field instanceof IGspCommonElement && field.getIsUdt() && !refEle.getIsFromAssoUdt()
              ? "addEnrichedRefProperty" : "addRefProperty");
      addRefPropertyNameArgs(refEle, invocation);
      addRefPropDisplayValueKeyArgs(refEle,invocation);
      addRefedPropertyNameArgs(refEle,invocation);
      block.statements().add(ast.newExpressionStatement(invocation));
    }
  }

  private void addRefPropDisplayValueKeyArgs(IGspCommonField refEle, MethodInvocation invocation) {
    if(isRefElementI18nPrefixEquals(refEle))
      return;
    StringLiteral stringLiteral=ast.newStringLiteral();
    stringLiteral.setLiteralValue(refEle.getI18nResourceInfoPrefix()+".Name");
    invocation.arguments().add(stringLiteral);
  }

  private boolean isRefElementI18nPrefixEquals(IGspCommonField refEle) {
    String fieldPrefix = field.getI18nResourceInfoPrefix();
    if(fieldPrefix==null||"".equals(fieldPrefix))
      return false;
    if ((fieldPrefix+"."+refEle.getLabelID()).equals(refEle.getI18nResourceInfoPrefix()))
        return true;
    return false;
  }

  protected void addRefedPropertyNameArgs(IGspCommonField refEle, MethodInvocation invocation) {
    GspCommonModel refModel = parentContext.getApiGenContext().getCefGenContext()
        .getMetadataContent("", refEle.getParentAssociation().getRefModelID());
    IGspCommonElement refElement = refModel.findElementById(refEle.getRefElementId());
    StringLiteral stringLiteral=ast.newStringLiteral();
    stringLiteral.setLiteralValue(refElement.getLabelID());
    invocation.arguments().add(stringLiteral);
  }

  protected final void addRefPropertyNameArgs(IGspCommonField refEle, MethodInvocation invocation) {
    StringLiteral stringLiteralProName =ast.newStringLiteral();
    stringLiteralProName.setLiteralValue(refEle.getLabelID());
    invocation.arguments().add(stringLiteralProName);
  }


  @Override
  protected String getMethodName() {
    return "addAssociationProperyInfo";
  }
}
